/*
 *  Copyright (C) 2011 in-somnia
 * 
 *  This file is part of JAAD.
 * 
 *  JAAD is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU Lesser General Public License as 
 *  published by the Free Software Foundation; either version 3 of the 
 *  License, or (at your option) any later version.
 *
 *  JAAD is distributed in the hope that it will be useful, but WITHOUT 
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General 
 *  Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library.
 *  If not, see <http://www.gnu.org/licenses/>.
 */
package net.sourceforge.jaad.aac.gain;

//complex FFT of length 128/16, inplace
class FFT {

	private static final float[][] FFT_TABLE_128 = {
		{1.0f, -0.0f},
		{0.99879545f, -0.049067676f},
		{0.9951847f, -0.09801714f},
		{0.9891765f, -0.14673047f},
		{0.98078525f, -0.19509032f},
		{0.97003126f, -0.24298018f},
		{0.95694035f, -0.29028466f},
		{0.94154406f, -0.33688986f},
		{0.9238795f, -0.38268343f},
		{0.9039893f, -0.42755508f},
		{0.8819213f, -0.47139674f},
		{0.8577286f, -0.51410276f},
		{0.8314696f, -0.55557024f},
		{0.8032075f, -0.5956993f},
		{0.77301043f, -0.6343933f},
		{0.7409511f, -0.671559f},
		{0.70710677f, -0.70710677f},
		{0.671559f, -0.7409511f},
		{0.6343933f, -0.77301043f},
		{0.5956993f, -0.8032075f},
		{0.55557024f, -0.8314696f},
		{0.51410276f, -0.8577286f},
		{0.47139674f, -0.8819213f},
		{0.42755508f, -0.9039893f},
		{0.38268343f, -0.9238795f},
		{0.33688986f, -0.94154406f},
		{0.29028466f, -0.95694035f},
		{0.24298018f, -0.97003126f},
		{0.19509032f, -0.98078525f},
		{0.14673047f, -0.9891765f},
		{0.09801714f, -0.9951847f},
		{0.049067676f, -0.99879545f},
		{6.123234E-17f, -1.0f},
		{-0.049067676f, -0.99879545f},
		{-0.09801714f, -0.9951847f},
		{-0.14673047f, -0.9891765f},
		{-0.19509032f, -0.98078525f},
		{-0.24298018f, -0.97003126f},
		{-0.29028466f, -0.95694035f},
		{-0.33688986f, -0.94154406f},
		{-0.38268343f, -0.9238795f},
		{-0.42755508f, -0.9039893f},
		{-0.47139674f, -0.8819213f},
		{-0.51410276f, -0.8577286f},
		{-0.55557024f, -0.8314696f},
		{-0.5956993f, -0.8032075f},
		{-0.6343933f, -0.77301043f},
		{-0.671559f, -0.7409511f},
		{-0.70710677f, -0.70710677f},
		{-0.7409511f, -0.671559f},
		{-0.77301043f, -0.6343933f},
		{-0.8032075f, -0.5956993f},
		{-0.8314696f, -0.55557024f},
		{-0.8577286f, -0.51410276f},
		{-0.8819213f, -0.47139674f},
		{-0.9039893f, -0.42755508f},
		{-0.9238795f, -0.38268343f},
		{-0.94154406f, -0.33688986f},
		{-0.95694035f, -0.29028466f},
		{-0.97003126f, -0.24298018f},
		{-0.98078525f, -0.19509032f},
		{-0.9891765f, -0.14673047f},
		{-0.9951847f, -0.09801714f},
		{-0.99879545f, -0.049067676f}
	};
	private static final float[][] FFT_TABLE_16 = {
		{1.0f, -0.0f},
		{0.9238795f, -0.38268343f},
		{0.70710677f, -0.70710677f},
		{0.38268343f, -0.9238795f},
		{6.123234E-17f, -1.0f},
		{-0.38268343f, -0.9238795f},
		{-0.70710677f, -0.70710677f},
		{-0.9238795f, -0.38268343f}
	};

	static void process(float[][] in, int n) {
		final int ln = (int) Math.round(Math.log(n)/Math.log(2));
		final float[][] table = (n==128) ? FFT_TABLE_128 : FFT_TABLE_16;

		//bit-reversal
		final float[][] rev = new float[n][2];
		int i, ii = 0;
		for(i = 0; i<n; i++) {
			rev[i][0] = in[ii][0];
			rev[i][1] = in[ii][1];
			int k = n>>1;
			while(ii>=k&&k>0) {
				ii -= k;
				k >>= 1;
			}
			ii += k;
		}
		for(i = 0; i<n; i++) {
			in[i][0] = rev[i][0];
			in[i][1] = rev[i][1];
		}

		//calculation
		int blocks = n/2;
		int size = 2;
		int j, k, l, k0, k1, size2;
		float[] a = new float[2];
		for(i = 0; i<ln; i++) {
			size2 = size/2;
			k0 = 0;
			k1 = size2;
			for(j = 0; j<blocks; ++j) {
				l = 0;
				for(k = 0; k<size2; ++k) {
					a[0] = in[k1][0]*table[l][0]-in[k1][1]*table[l][1];
					a[1] = in[k1][0]*table[l][1]+in[k1][1]*table[l][0];
					in[k1][0] = in[k0][0]-a[0];
					in[k1][1] = in[k0][1]-a[1];
					in[k0][0] += a[0];
					in[k0][1] += a[1];
					l += blocks;
					k0++;
					k1++;
				}
				k0 += size2;
				k1 += size2;
			}
			blocks = blocks/2;
			size = size*2;
		}
	}
}
